if HAVE_VULKAN
gsk_private_vulkan_source_h = \
gskvulkanblendpipelineprivate.h \
+ gskvulkanborderpipelineprivate.h \
gskvulkanbufferprivate.h \
gskvulkanclipprivate.h \
gskvulkancolorpipelineprivate.h \
gskvulkanshaderprivate.h
gsk_private_vulkan_source_c = \
gskvulkanblendpipeline.c \
+ gskvulkanborderpipeline.c \
gskvulkanbuffer.c \
gskvulkanclip.c \
gskvulkancolorpipeline.c \
gskvulkanrenderer.c \
gskvulkanrenderpass.c \
gskvulkanshader.c
+gsk_private_vulkan_include_shaders = \
+ resources/vulkan/rounded-rect.glsl
gsk_private_vulkan_shaders = \
resources/vulkan/blend-clip.frag.glsl \
resources/vulkan/blend-clip-rounded.frag.glsl \
resources/vulkan/blend-clip.vert.glsl \
resources/vulkan/blend.frag.glsl \
resources/vulkan/blend.vert.glsl \
+ resources/vulkan/border-clip.frag.glsl \
+ resources/vulkan/border-clip.vert.glsl \
+ resources/vulkan/border-clip-rounded.frag.glsl \
+ resources/vulkan/border-clip-rounded.vert.glsl \
+ resources/vulkan/border.frag.glsl \
+ resources/vulkan/border.vert.glsl \
resources/vulkan/color-clip.frag.glsl \
resources/vulkan/color-clip-rounded.frag.glsl \
resources/vulkan/color-clip-rounded.vert.glsl \
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $< \
--target=$@ --sourcedir=$(srcdir) --c-name _gsk --generate-source --manual-register
-EXTRA_DIST += $(resource_files)
+EXTRA_DIST += $(resource_files) $(gsk_private_vulkan_include_shaders)
CLEANFILES += gsk.resources.xml
DISTCLEANFILES += gskresources.h gskresources.c
return &self->outline;
}
-float
-gsk_border_node_get_width (GskRenderNode *node,
- guint i)
+const float *
+gsk_border_node_peek_widths (GskRenderNode *node)
{
GskBorderNode *self = (GskBorderNode *) node;
- return self->border_width[i];
+ return self->border_width;
}
const GdkRGBA *
-gsk_border_node_peek_color (GskRenderNode *node,
- guint i)
+gsk_border_node_peek_colors (GskRenderNode *node)
{
GskBorderNode *self = (GskBorderNode *) node;
- return &self->border_color[i];
+ return self->border_color;
}
/**
const GskColorStop * gsk_linear_gradient_node_peek_color_stops (GskRenderNode *node);
const GskRoundedRect * gsk_border_node_peek_outline (GskRenderNode *node);
-float gsk_border_node_get_width (GskRenderNode *node, guint i);
-const GdkRGBA * gsk_border_node_peek_color (GskRenderNode *node, guint i);
+const float * gsk_border_node_peek_widths (GskRenderNode *node);
+const GdkRGBA * gsk_border_node_peek_colors (GskRenderNode *node);
GskRenderNode *gsk_cairo_node_new_for_surface (const graphene_rect_t *bounds, cairo_surface_t *surface);
cairo_surface_t *gsk_cairo_node_get_surface (GskRenderNode *node);
--- /dev/null
+#include "config.h"
+
+#include "gskvulkanborderpipelineprivate.h"
+
+#include "gskroundedrectprivate.h"
+
+struct _GskVulkanBorderPipeline
+{
+ GObject parent_instance;
+};
+
+typedef struct _GskVulkanBorderInstance GskVulkanBorderInstance;
+
+struct _GskVulkanBorderInstance
+{
+ float rect[12];
+ float widths[4];
+ float colors[16];
+};
+
+G_DEFINE_TYPE (GskVulkanBorderPipeline, gsk_vulkan_border_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_border_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+ static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+ {
+ .binding = 0,
+ .stride = sizeof (GskVulkanBorderInstance),
+ .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+ }
+ };
+ static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+ {
+ .location = 0,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect),
+ },
+ {
+ .location = 1,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 4 * sizeof (float),
+ },
+ {
+ .location = 2,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 8 * sizeof (float),
+ },
+ {
+ .location = 3,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, widths),
+ },
+ {
+ .location = 4,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors),
+ },
+ {
+ .location = 5,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 4 * sizeof (float),
+ },
+ {
+ .location = 6,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 8 * sizeof (float),
+ },
+ {
+ .location = 7,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 12 * sizeof (float),
+ }
+ };
+ static const VkPipelineVertexInputStateCreateInfo info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+ .pVertexBindingDescriptions = vertexBindingDescriptions,
+ .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+ .pVertexAttributeDescriptions = vertexInputAttributeDescription
+ };
+
+ return &info;
+}
+
+static void
+gsk_vulkan_border_pipeline_finalize (GObject *gobject)
+{
+ //GskVulkanBorderPipeline *self = GSK_VULKAN_BORDER_PIPELINE (gobject);
+
+ G_OBJECT_CLASS (gsk_vulkan_border_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_border_pipeline_class_init (GskVulkanBorderPipelineClass *klass)
+{
+ GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+ G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_border_pipeline_finalize;
+
+ pipeline_class->get_input_state_create_info = gsk_vulkan_border_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_border_pipeline_init (GskVulkanBorderPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_border_pipeline_new (GskVulkanPipelineLayout *layout,
+ const char *shader_name,
+ VkRenderPass render_pass)
+{
+ return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BORDER_PIPELINE, layout, shader_name, render_pass);
+}
+
+gsize
+gsk_vulkan_border_pipeline_count_vertex_data (GskVulkanBorderPipeline *pipeline)
+{
+ return sizeof (GskVulkanBorderInstance);
+}
+
+void
+gsk_vulkan_border_pipeline_collect_vertex_data (GskVulkanBorderPipeline *pipeline,
+ guchar *data,
+ const GskRoundedRect *rect,
+ const float widths[4],
+ const GdkRGBA colors[4])
+{
+ GskVulkanBorderInstance *instance = (GskVulkanBorderInstance *) data;
+ guint i;
+
+ gsk_rounded_rect_to_float (rect, instance->rect);
+ for (i = 0; i < 4; i++)
+ {
+ instance->widths[i] = widths[i];
+ instance->colors[4 * i + 0] = colors[i].red;
+ instance->colors[4 * i + 1] = colors[i].green;
+ instance->colors[4 * i + 2] = colors[i].blue;
+ instance->colors[4 * i + 3] = colors[i].alpha;
+ }
+}
+
+gsize
+gsk_vulkan_border_pipeline_draw (GskVulkanBorderPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands)
+{
+ vkCmdDraw (command_buffer,
+ 6 * 8, n_commands,
+ 0, offset);
+
+ return n_commands;
+}
--- /dev/null
+#ifndef __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+#include "gskroundedrect.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanBorderPipelineLayout GskVulkanBorderPipelineLayout;
+
+#define GSK_TYPE_VULKAN_BORDER_PIPELINE (gsk_vulkan_border_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanBorderPipeline, gsk_vulkan_border_pipeline, GSK, VULKAN_BORDER_PIPELINE, GskVulkanPipeline)
+
+GskVulkanPipeline * gsk_vulkan_border_pipeline_new (GskVulkanPipelineLayout * layout,
+ const char *shader_name,
+ VkRenderPass render_pass);
+
+gsize gsk_vulkan_border_pipeline_count_vertex_data (GskVulkanBorderPipeline *pipeline);
+void gsk_vulkan_border_pipeline_collect_vertex_data (GskVulkanBorderPipeline *pipeline,
+ guchar *data,
+ const GskRoundedRect *rect,
+ const float widths[4],
+ const GdkRGBA colors[4]);
+gsize gsk_vulkan_border_pipeline_draw (GskVulkanBorderPipeline *pipeline,
+ VkCommandBuffer command_buffer,
+ gsize offset,
+ gsize n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__ */
#include "gskvulkanrenderpassprivate.h"
#include "gskvulkanblendpipelineprivate.h"
+#include "gskvulkanborderpipelineprivate.h"
#include "gskvulkancolorpipelineprivate.h"
#include "gskvulkaneffectpipelineprivate.h"
#include "gskvulkanlineargradientpipelineprivate.h"
{ "linear-clip-rounded", gsk_vulkan_linear_gradient_pipeline_new },
{ "color-matrix", gsk_vulkan_effect_pipeline_new },
{ "color-matrix-clip", gsk_vulkan_effect_pipeline_new },
- { "color-matrix-clip-rounded", gsk_vulkan_effect_pipeline_new }
+ { "color-matrix-clip-rounded", gsk_vulkan_effect_pipeline_new },
+ { "border", gsk_vulkan_border_pipeline_new },
+ { "border-clip", gsk_vulkan_border_pipeline_new },
+ { "border-clip-rounded", gsk_vulkan_border_pipeline_new }
};
g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL);
#include "gskrenderer.h"
#include "gskroundedrectprivate.h"
#include "gskvulkanblendpipelineprivate.h"
+#include "gskvulkanborderpipelineprivate.h"
#include "gskvulkanclipprivate.h"
#include "gskvulkancolorpipelineprivate.h"
#include "gskvulkaneffectpipelineprivate.h"
GSK_VULKAN_OP_LINEAR_GRADIENT,
GSK_VULKAN_OP_OPACITY,
GSK_VULKAN_OP_COLOR_MATRIX,
+ GSK_VULKAN_OP_BORDER,
/* GskVulkanOpPushConstants */
GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS
} GskVulkanOpType;
case GSK_NOT_A_RENDER_NODE:
g_assert_not_reached ();
return;
- case GSK_BORDER_NODE:
case GSK_INSET_SHADOW_NODE:
case GSK_OUTSET_SHADOW_NODE:
+ case GSK_REPEAT_NODE:
case GSK_SHADOW_NODE:
case GSK_BLEND_NODE:
case GSK_CROSS_FADE_NODE:
g_array_append_val (self->render_ops, op);
return;
+ case GSK_BORDER_NODE:
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_BORDER;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED;
+ else
+ FALLBACK ("Border nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_BORDER;
+ op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
+ g_array_append_val (self->render_ops, op);
+ return;
+
case GSK_CONTAINER_NODE:
{
guint i;
case GSK_VULKAN_OP_COLOR:
case GSK_VULKAN_OP_LINEAR_GRADIENT:
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
+ case GSK_VULKAN_OP_BORDER:
break;
}
}
n_bytes += op->render.vertex_count;
break;
+ case GSK_VULKAN_OP_BORDER:
+ op->render.vertex_count = gsk_vulkan_border_pipeline_count_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline));
+ n_bytes += op->render.vertex_count;
+ break;
+
default:
g_assert_not_reached ();
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
}
break;
+ case GSK_VULKAN_OP_BORDER:
+ {
+ op->render.vertex_offset = offset + n_bytes;
+ gsk_vulkan_border_pipeline_collect_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline),
+ data + n_bytes + offset,
+ gsk_border_node_peek_outline (op->render.node),
+ gsk_border_node_peek_widths (op->render.node),
+ gsk_border_node_peek_colors (op->render.node));
+ n_bytes += op->render.vertex_count;
+ }
+ break;
+
default:
g_assert_not_reached ();
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
case GSK_VULKAN_OP_COLOR:
case GSK_VULKAN_OP_LINEAR_GRADIENT:
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
+ case GSK_VULKAN_OP_BORDER:
break;
}
}
current_draw_index, 1);
break;
+ case GSK_VULKAN_OP_BORDER:
+ if (current_pipeline != op->render.pipeline)
+ {
+ current_pipeline = op->render.pipeline;
+ vkCmdBindPipeline (command_buffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+ vkCmdBindVertexBuffers (command_buffer,
+ 0,
+ 1,
+ (VkBuffer[1]) {
+ gsk_vulkan_buffer_get_buffer (vertex_buffer)
+ },
+ (VkDeviceSize[1]) { op->render.vertex_offset });
+ current_draw_index = 0;
+ }
+ current_draw_index += gsk_vulkan_border_pipeline_draw (GSK_VULKAN_BORDER_PIPELINE (current_pipeline),
+ command_buffer,
+ current_draw_index, 1);
+ break;
+
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
gsk_vulkan_push_constants_push_vertex (&op->constants.constants,
command_buffer,
GSK_VULKAN_PIPELINE_COLOR_MATRIX,
GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP,
GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED,
+ GSK_VULKAN_PIPELINE_BORDER,
+ GSK_VULKAN_PIPELINE_BORDER_CLIP,
+ GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED,
/* add more */
GSK_VULKAN_N_PIPELINES
} GskVulkanPipelineType;
--- /dev/null
+#version 420 core
+
+#include "rounded-rect.glsl"
+
+layout(location = 0) in vec2 inPos;
+layout(location = 1) in vec4 inColor;
+layout(location = 2) in vec4 inRect;
+layout(location = 3) in vec4 inCornerWidths;
+layout(location = 4) in vec4 inCornerHeights;
+layout(location = 5) in vec4 inBorderWidths;
+layout(location = 6) in flat vec4 inClipBounds;
+layout(location = 7) in flat vec4 inClipWidths;
+layout(location = 8) in flat vec4 inClipHeights;
+
+layout(location = 0) out vec4 color;
+
+vec4
+clip (vec4 color)
+{
+ RoundedRect r = RoundedRect (vec4(inClipBounds.xy, inClipBounds.xy + inClipBounds.zw), inClipWidths, inClipHeights);
+
+ return color * rounded_rect_coverage (r, inPos);
+}
+
+void main()
+{
+ RoundedRect routside = RoundedRect (vec4(inRect.xy, inRect.xy + inRect.zw), inCornerWidths, inCornerHeights);
+ RoundedRect rinside = rounded_rect_shrink (routside, inBorderWidths);
+
+ float alpha = clamp (rounded_rect_coverage (routside, inPos) -
+ rounded_rect_coverage (rinside, inPos),
+ 0.0, 1.0);
+ color = clip (inColor);
+}
--- /dev/null
+#version 420 core
+
+layout(location = 0) in vec4 inRect;
+layout(location = 1) in vec4 inCornerWidths;
+layout(location = 2) in vec4 inCornerHeights;
+layout(location = 3) in vec4 inBorderWidths;
+layout(location = 4) in mat4 inBorderColors;
+
+layout(push_constant) uniform PushConstants {
+ mat4 mvp;
+ vec4 clip_bounds;
+ vec4 clip_widths;
+ vec4 clip_heights;
+} push;
+
+layout(location = 0) out vec2 outPos;
+layout(location = 1) out flat vec4 outColor;
+layout(location = 2) out flat vec4 outRect;
+layout(location = 3) out flat vec4 outCornerWidths;
+layout(location = 4) out flat vec4 outCornerHeights;
+layout(location = 5) out flat vec4 outBorderWidths;
+layout(location = 6) out flat vec4 outClipBounds;
+layout(location = 7) out flat vec4 outClipWidths;
+layout(location = 8) out flat vec4 outClipHeights;
+
+out gl_PerVertex {
+ vec4 gl_Position;
+};
+
+vec2 offsets[6] = { vec2(0.0, 0.0),
+ vec2(1.0, 0.0),
+ vec2(0.0, 1.0),
+ vec2(1.0, 1.0),
+ vec2(0.0, 1.0),
+ vec2(1.0, 0.0) };
+
+#define TOP 0
+#define RIGHT 1
+#define BOTTOM 2
+#define LEFT 3
+
+#define TOP_LEFT 0
+#define TOP_RIGHT 1
+#define BOTTOM_RIGHT 2
+#define BOTTOM_LEFT 3
+
+#define SLICE_TOP_LEFT 0
+#define SLICE_TOP 1
+#define SLICE_TOP_RIGHT 2
+#define SLICE_RIGHT 3
+#define SLICE_BOTTOM_RIGHT 4
+#define SLICE_BOTTOM 5
+#define SLICE_BOTTOM_LEFT 6
+#define SLICE_LEFT 7
+
+vec4 intersect(vec4 a, vec4 b)
+{
+ a = vec4(a.xy, a.xy + a.zw);
+ b = vec4(b.xy, b.xy + b.zw);
+ vec4 result = vec4(max(a.xy, b.xy), min(a.zw, b.zw));
+ if (any (greaterThanEqual (result.xy, result.zw)))
+ return vec4(0.0,0.0,0.0,0.0);
+ return vec4(result.xy, result.zw - result.xy);
+}
+
+void main() {
+ int slice_index = gl_VertexIndex / 6;
+ int vert_index = gl_VertexIndex % 6;
+
+ vec4 corner_widths = max (inCornerWidths, inBorderWidths.wyyw);
+ vec4 corner_heights = max (inCornerHeights, inBorderWidths.xxzz);
+
+ vec4 rect;
+
+ switch (slice_index)
+ {
+ case SLICE_TOP_LEFT:
+ rect = vec4(inRect.xy, corner_widths[TOP_LEFT], corner_heights[TOP_LEFT]);
+ vert_index = (vert_index + 3) % 6;
+ break;
+ case SLICE_TOP:
+ rect = vec4(inRect.x + corner_widths[TOP_LEFT], inRect.y, inRect.z - corner_widths[TOP_LEFT] - corner_widths[TOP_RIGHT], inBorderWidths[TOP]);
+ outColor = inBorderColors[TOP];
+ break;
+ case SLICE_TOP_RIGHT:
+ rect = vec4(inRect.x + inRect.z - corner_widths[TOP_RIGHT], inRect.y, corner_widths[TOP_RIGHT], corner_heights[TOP_RIGHT]);
+ break;
+ case SLICE_RIGHT:
+ rect = vec4(inRect.x + inRect.z - inBorderWidths[RIGHT], inRect.y + corner_heights[TOP_RIGHT], inBorderWidths[RIGHT], inRect.w - corner_heights[TOP_RIGHT] - corner_heights[BOTTOM_RIGHT]);
+ outColor = inBorderColors[RIGHT];
+ break;
+ case SLICE_BOTTOM_RIGHT:
+ rect = vec4(inRect.x + inRect.z - corner_widths[BOTTOM_RIGHT], inRect.y + inRect.w - corner_heights[BOTTOM_RIGHT], corner_widths[BOTTOM_RIGHT], corner_heights[BOTTOM_RIGHT]);
+ break;
+ case SLICE_BOTTOM:
+ rect = vec4(inRect.x + corner_widths[BOTTOM_LEFT], inRect.y + inRect.w - inBorderWidths[BOTTOM], inRect.z - corner_widths[BOTTOM_LEFT] - corner_widths[BOTTOM_RIGHT], inBorderWidths[BOTTOM]);
+ break;
+ case SLICE_BOTTOM_LEFT:
+ rect = vec4(inRect.x, inRect.y + inRect.w - corner_heights[BOTTOM_LEFT], corner_widths[BOTTOM_LEFT], corner_heights[BOTTOM_LEFT]);
+ vert_index = (vert_index + 3) % 6;
+ break;
+ case SLICE_LEFT:
+ rect = vec4(inRect.x, inRect.y + corner_heights[TOP_LEFT], inBorderWidths[LEFT], inRect.w - corner_heights[TOP_LEFT] - corner_heights[BOTTOM_LEFT]);
+ break;
+ }
+
+ rect = intersect (rect, push.clip_bounds);
+ vec2 pos;
+ if ((slice_index % 4) != 0 || (vert_index % 3) != 2)
+ pos = rect.xy + rect.zw * offsets[vert_index];
+ else
+ pos = rect.xy + rect.zw * vec2(1.0 - offsets[vert_index].x, offsets[vert_index].y);
+ gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
+ outColor = inBorderColors[((gl_VertexIndex / 3 + 15) / 4) % 4];
+ outPos = pos;
+ outRect = inRect;
+ outCornerWidths = inCornerWidths;
+ outCornerHeights = inCornerHeights;
+ outBorderWidths = inBorderWidths;
+ outClipBounds = push.clip_bounds;
+ outClipWidths = push.clip_widths;
+ outClipHeights = push.clip_heights;
+}
--- /dev/null
+#version 420 core
+
+#include "rounded-rect.glsl"
+
+layout(location = 0) in vec2 inPos;
+layout(location = 1) in flat vec4 inColor;
+layout(location = 2) in flat vec4 inRect;
+layout(location = 3) in flat vec4 inCornerWidths;
+layout(location = 4) in flat vec4 inCornerHeights;
+layout(location = 5) in flat vec4 inBorderWidths;
+
+layout(location = 0) out vec4 color;
+
+void main()
+{
+ RoundedRect routside = RoundedRect (vec4(inRect.xy, inRect.xy + inRect.zw), inCornerWidths, inCornerHeights);
+ RoundedRect rinside = rounded_rect_shrink (routside, inBorderWidths);
+
+ float alpha = clamp (rounded_rect_coverage (routside, inPos) -
+ rounded_rect_coverage (rinside, inPos),
+ 0.0, 1.0);
+ color = inColor * alpha;
+}
--- /dev/null
+#version 420 core
+
+layout(location = 0) in vec4 inRect;
+layout(location = 1) in vec4 inCornerWidths;
+layout(location = 2) in vec4 inCornerHeights;
+layout(location = 3) in vec4 inBorderWidths;
+layout(location = 4) in mat4 inBorderColors;
+
+layout(push_constant) uniform PushConstants {
+ mat4 mvp;
+ vec4 clip_bounds;
+ vec4 clip_widths;
+ vec4 clip_heights;
+} push;
+
+layout(location = 0) out vec2 outPos;
+layout(location = 1) out flat vec4 outColor;
+layout(location = 2) out flat vec4 outRect;
+layout(location = 3) out flat vec4 outCornerWidths;
+layout(location = 4) out flat vec4 outCornerHeights;
+layout(location = 5) out flat vec4 outBorderWidths;
+
+out gl_PerVertex {
+ vec4 gl_Position;
+};
+
+vec2 offsets[6] = { vec2(0.0, 0.0),
+ vec2(1.0, 0.0),
+ vec2(0.0, 1.0),
+ vec2(1.0, 1.0),
+ vec2(0.0, 1.0),
+ vec2(1.0, 0.0) };
+
+#define TOP 0
+#define RIGHT 1
+#define BOTTOM 2
+#define LEFT 3
+
+#define TOP_LEFT 0
+#define TOP_RIGHT 1
+#define BOTTOM_RIGHT 2
+#define BOTTOM_LEFT 3
+
+#define SLICE_TOP_LEFT 0
+#define SLICE_TOP 1
+#define SLICE_TOP_RIGHT 2
+#define SLICE_RIGHT 3
+#define SLICE_BOTTOM_RIGHT 4
+#define SLICE_BOTTOM 5
+#define SLICE_BOTTOM_LEFT 6
+#define SLICE_LEFT 7
+
+vec4 intersect(vec4 a, vec4 b)
+{
+ a = vec4(a.xy, a.xy + a.zw);
+ b = vec4(b.xy, b.xy + b.zw);
+ vec4 result = vec4(max(a.xy, b.xy), min(a.zw, b.zw));
+ if (any (greaterThanEqual (result.xy, result.zw)))
+ return vec4(0.0,0.0,0.0,0.0);
+ return vec4(result.xy, result.zw - result.xy);
+}
+
+void main() {
+ int slice_index = gl_VertexIndex / 6;
+ int vert_index = gl_VertexIndex % 6;
+
+ vec4 corner_widths = max (inCornerWidths, inBorderWidths.wyyw);
+ vec4 corner_heights = max (inCornerHeights, inBorderWidths.xxzz);
+
+ vec4 rect;
+
+ switch (slice_index)
+ {
+ case SLICE_TOP_LEFT:
+ rect = vec4(inRect.xy, corner_widths[TOP_LEFT], corner_heights[TOP_LEFT]);
+ vert_index = (vert_index + 3) % 6;
+ break;
+ case SLICE_TOP:
+ rect = vec4(inRect.x + corner_widths[TOP_LEFT], inRect.y, inRect.z - corner_widths[TOP_LEFT] - corner_widths[TOP_RIGHT], inBorderWidths[TOP]);
+ outColor = inBorderColors[TOP];
+ break;
+ case SLICE_TOP_RIGHT:
+ rect = vec4(inRect.x + inRect.z - corner_widths[TOP_RIGHT], inRect.y, corner_widths[TOP_RIGHT], corner_heights[TOP_RIGHT]);
+ break;
+ case SLICE_RIGHT:
+ rect = vec4(inRect.x + inRect.z - inBorderWidths[RIGHT], inRect.y + corner_heights[TOP_RIGHT], inBorderWidths[RIGHT], inRect.w - corner_heights[TOP_RIGHT] - corner_heights[BOTTOM_RIGHT]);
+ outColor = inBorderColors[RIGHT];
+ break;
+ case SLICE_BOTTOM_RIGHT:
+ rect = vec4(inRect.x + inRect.z - corner_widths[BOTTOM_RIGHT], inRect.y + inRect.w - corner_heights[BOTTOM_RIGHT], corner_widths[BOTTOM_RIGHT], corner_heights[BOTTOM_RIGHT]);
+ break;
+ case SLICE_BOTTOM:
+ rect = vec4(inRect.x + corner_widths[BOTTOM_LEFT], inRect.y + inRect.w - inBorderWidths[BOTTOM], inRect.z - corner_widths[BOTTOM_LEFT] - corner_widths[BOTTOM_RIGHT], inBorderWidths[BOTTOM]);
+ break;
+ case SLICE_BOTTOM_LEFT:
+ rect = vec4(inRect.x, inRect.y + inRect.w - corner_heights[BOTTOM_LEFT], corner_widths[BOTTOM_LEFT], corner_heights[BOTTOM_LEFT]);
+ vert_index = (vert_index + 3) % 6;
+ break;
+ case SLICE_LEFT:
+ rect = vec4(inRect.x, inRect.y + corner_heights[TOP_LEFT], inBorderWidths[LEFT], inRect.w - corner_heights[TOP_LEFT] - corner_heights[BOTTOM_LEFT]);
+ break;
+ }
+
+ rect = intersect (rect, push.clip_bounds);
+ vec2 pos;
+ if ((slice_index % 4) != 0 || (vert_index % 3) != 2)
+ pos = rect.xy + rect.zw * offsets[vert_index];
+ else
+ pos = rect.xy + rect.zw * vec2(1.0 - offsets[vert_index].x, offsets[vert_index].y);
+ gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
+ outColor = inBorderColors[((gl_VertexIndex / 3 + 15) / 4) % 4];
+ outPos = pos;
+ outRect = inRect;
+ outCornerWidths = inCornerWidths;
+ outCornerHeights = inCornerHeights;
+ outBorderWidths = inBorderWidths;
+}
--- /dev/null
+#version 420 core
+
+#include "rounded-rect.glsl"
+
+layout(location = 0) in vec2 inPos;
+layout(location = 1) in flat vec4 inColor;
+layout(location = 2) in flat vec4 inRect;
+layout(location = 3) in flat vec4 inCornerWidths;
+layout(location = 4) in flat vec4 inCornerHeights;
+layout(location = 5) in flat vec4 inBorderWidths;
+
+layout(location = 0) out vec4 color;
+
+void main()
+{
+ RoundedRect routside = RoundedRect (vec4(inRect.xy, inRect.xy + inRect.zw), inCornerWidths, inCornerHeights);
+ RoundedRect rinside = rounded_rect_shrink (routside, inBorderWidths);
+
+ float alpha = clamp (rounded_rect_coverage (routside, inPos) -
+ rounded_rect_coverage (rinside, inPos),
+ 0.0, 1.0);
+ color = inColor * alpha;
+}
--- /dev/null
+#version 420 core
+
+layout(location = 0) in vec4 inRect;
+layout(location = 1) in vec4 inCornerWidths;
+layout(location = 2) in vec4 inCornerHeights;
+layout(location = 3) in vec4 inBorderWidths;
+layout(location = 4) in mat4 inBorderColors;
+
+layout(push_constant) uniform PushConstants {
+ mat4 mvp;
+ vec4 clip_bounds;
+ vec4 clip_widths;
+ vec4 clip_heights;
+} push;
+
+layout(location = 0) out vec2 outPos;
+layout(location = 1) out flat vec4 outColor;
+layout(location = 2) out flat vec4 outRect;
+layout(location = 3) out flat vec4 outCornerWidths;
+layout(location = 4) out flat vec4 outCornerHeights;
+layout(location = 5) out flat vec4 outBorderWidths;
+
+out gl_PerVertex {
+ vec4 gl_Position;
+};
+
+vec2 offsets[6] = { vec2(0.0, 0.0),
+ vec2(1.0, 0.0),
+ vec2(0.0, 1.0),
+ vec2(1.0, 1.0),
+ vec2(0.0, 1.0),
+ vec2(1.0, 0.0) };
+
+#define TOP 0
+#define RIGHT 1
+#define BOTTOM 2
+#define LEFT 3
+
+#define TOP_LEFT 0
+#define TOP_RIGHT 1
+#define BOTTOM_RIGHT 2
+#define BOTTOM_LEFT 3
+
+#define SLICE_TOP_LEFT 0
+#define SLICE_TOP 1
+#define SLICE_TOP_RIGHT 2
+#define SLICE_RIGHT 3
+#define SLICE_BOTTOM_RIGHT 4
+#define SLICE_BOTTOM 5
+#define SLICE_BOTTOM_LEFT 6
+#define SLICE_LEFT 7
+
+void main() {
+ int slice_index = gl_VertexIndex / 6;
+ int vert_index = gl_VertexIndex % 6;
+
+ vec4 corner_widths = max (inCornerWidths, inBorderWidths.wyyw);
+ vec4 corner_heights = max (inCornerHeights, inBorderWidths.xxzz);
+
+ vec4 rect;
+
+ switch (slice_index)
+ {
+ case SLICE_TOP_LEFT:
+ rect = vec4(inRect.xy, corner_widths[TOP_LEFT], corner_heights[TOP_LEFT]);
+ vert_index = (vert_index + 3) % 6;
+ break;
+ case SLICE_TOP:
+ rect = vec4(inRect.x + corner_widths[TOP_LEFT], inRect.y, inRect.z - corner_widths[TOP_LEFT] - corner_widths[TOP_RIGHT], inBorderWidths[TOP]);
+ outColor = inBorderColors[TOP];
+ break;
+ case SLICE_TOP_RIGHT:
+ rect = vec4(inRect.x + inRect.z - corner_widths[TOP_RIGHT], inRect.y, corner_widths[TOP_RIGHT], corner_heights[TOP_RIGHT]);
+ break;
+ case SLICE_RIGHT:
+ rect = vec4(inRect.x + inRect.z - inBorderWidths[RIGHT], inRect.y + corner_heights[TOP_RIGHT], inBorderWidths[RIGHT], inRect.w - corner_heights[TOP_RIGHT] - corner_heights[BOTTOM_RIGHT]);
+ outColor = inBorderColors[RIGHT];
+ break;
+ case SLICE_BOTTOM_RIGHT:
+ rect = vec4(inRect.x + inRect.z - corner_widths[BOTTOM_RIGHT], inRect.y + inRect.w - corner_heights[BOTTOM_RIGHT], corner_widths[BOTTOM_RIGHT], corner_heights[BOTTOM_RIGHT]);
+ break;
+ case SLICE_BOTTOM:
+ rect = vec4(inRect.x + corner_widths[BOTTOM_LEFT], inRect.y + inRect.w - inBorderWidths[BOTTOM], inRect.z - corner_widths[BOTTOM_LEFT] - corner_widths[BOTTOM_RIGHT], inBorderWidths[BOTTOM]);
+ break;
+ case SLICE_BOTTOM_LEFT:
+ rect = vec4(inRect.x, inRect.y + inRect.w - corner_heights[BOTTOM_LEFT], corner_widths[BOTTOM_LEFT], corner_heights[BOTTOM_LEFT]);
+ vert_index = (vert_index + 3) % 6;
+ break;
+ case SLICE_LEFT:
+ rect = vec4(inRect.x, inRect.y + corner_heights[TOP_LEFT], inBorderWidths[LEFT], inRect.w - corner_heights[TOP_LEFT] - corner_heights[BOTTOM_LEFT]);
+ break;
+ }
+
+ vec2 pos;
+ if ((slice_index % 4) != 0 || (vert_index % 3) != 2)
+ pos = rect.xy + rect.zw * offsets[vert_index];
+ else
+ pos = rect.xy + rect.zw * vec2(1.0 - offsets[vert_index].x, offsets[vert_index].y);
+ gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
+ outColor = inBorderColors[((gl_VertexIndex / 3 + 15) / 4) % 4];
+ outPos = pos;
+ outRect = inRect;
+ outCornerWidths = inCornerWidths;
+ outCornerHeights = inCornerHeights;
+ outBorderWidths = inBorderWidths;
+}
--- /dev/null
+#ifndef _ROUNDED_RECT_
+#define _ROUNDED_RECT_
+
+struct RoundedRect
+{
+ vec4 bounds;
+ vec4 corner_widths;
+ vec4 corner_heights;
+};
+
+float
+ellipsis_dist (vec2 p, vec2 radius)
+{
+ vec2 p0 = p / radius;
+ vec2 p1 = 2.0 * p0 / radius;
+
+ return (dot(p0, p0) - 1.0) / length (p1);
+}
+
+float
+ellipsis_coverage (vec2 point, vec2 center, vec2 radius)
+{
+ float d = ellipsis_dist (point - center, radius);
+ return clamp (0.5 - d, 0.0, 1.0);
+}
+
+float
+rounded_rect_coverage (RoundedRect r, vec2 p)
+{
+ if (p.x < r.bounds.x || p.y < r.bounds.y ||
+ p.x >= r.bounds.z || p.y >= r.bounds.w)
+ return 0.0;
+
+ vec2 rad_tl = vec2(r.corner_widths.x, r.corner_heights.x);
+ vec2 rad_tr = vec2(r.corner_widths.y, r.corner_heights.y);
+ vec2 rad_br = vec2(r.corner_widths.z, r.corner_heights.z);
+ vec2 rad_bl = vec2(r.corner_widths.w, r.corner_heights.w);
+
+ vec2 ref_tl = r.bounds.xy + vec2( r.corner_widths.x, r.corner_heights.x);
+ vec2 ref_tr = r.bounds.zy + vec2(-r.corner_widths.y, r.corner_heights.y);
+ vec2 ref_br = r.bounds.zw + vec2(-r.corner_widths.z, -r.corner_heights.z);
+ vec2 ref_bl = r.bounds.xw + vec2( r.corner_widths.w, -r.corner_heights.w);
+
+ float d_tl = ellipsis_coverage(p, ref_tl, rad_tl);
+ float d_tr = ellipsis_coverage(p, ref_tr, rad_tr);
+ float d_br = ellipsis_coverage(p, ref_br, rad_br);
+ float d_bl = ellipsis_coverage(p, ref_bl, rad_bl);
+
+ vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl);
+
+ bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y,
+ p.x > ref_tr.x && p.y < ref_tr.y,
+ p.x > ref_br.x && p.y > ref_br.y,
+ p.x < ref_bl.x && p.y > ref_bl.y);
+
+ return 1.0 - dot(vec4(is_out), corner_coverages);
+}
+
+RoundedRect
+rounded_rect_shrink (RoundedRect r, vec4 amount)
+{
+ vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz;
+ vec4 new_widths = max (r.corner_widths - amount.wyyw, 0.0);
+ vec4 new_heights = max (r.corner_heights - amount.xxzz, 0.0);
+
+ return RoundedRect (new_bounds, new_widths, new_heights);
+}
+
+#endif